package com.leon.learnenginespace.drools.utils;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.leon.learnenginespace.drools.pojo.CreateRuleModel;
import com.leon.learnenginespace.drools.pojo.TDrlDictionary;
import com.leon.learnenginespace.drools.pojo.TDrlFieldConfig;
import lombok.extern.slf4j.Slf4j;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.utils.KieHelper;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 字段规则生成器
 *
 */
@Slf4j
@Component
public class RuleUtils {

    public static void main(String[] args) {
        String key = "aaa.aaa.aaa#.aaa#.bb";
        RuleUtils f = new RuleUtils();
        JSONObject body = new JSONObject();
        RuleCoverJsonUtils.encap(key, body, 1);

        //body.getJSONArray()
        System.out.println(body.toJSONString());
        String ruleStr = null;//f.createRule(1L, key,1 , "equalsModel", null, "bb不能为空");
        KieBase fieldKieBase = f.load(ruleStr);
        System.out.println(ruleStr);
        KieSession kieSession = fieldKieBase.newKieSession();
        kieSession.insert(body);
        int firedCount = kieSession.fireAllRules();
        kieSession.dispose();
        System.out.println(firedCount);
    }

    public KieBase load(String rule) {
        log.info("正在加载规则.....");
        KieHelper kieHelper = new KieHelper();
        kieHelper.addContent(rule, ResourceType.DRL);
        KieBase build = null;
        try {
            build = kieHelper.build();
        } catch (Exception e) {
            log.error("规则加载出错！");
            log.error(e.getMessage(), e);
            log.error(e.getMessage(),e);
            throw new ParamException("规则内容错误，请修改规则内容");
        }
        log.info("规则加载完成！");
        //   fieldKieBase = build;
        return build;

    }

    public String createRule(Long num, CreateRuleModel createRuleModel, List<ModelEntity> modelEntityList, String warningInfo) {

        if (num == null) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        build(createRuleModel, builder, modelEntityList);
        //String model = "cc.bb==1";
        String rule = "package com.field;\n" +
                "import com.alibaba.fastjson.JSONObject;\n" +
                "import com.alibaba.fastjson.JSONArray;\n" +
                "import com.sinosoft.msf.utils.OperationUtils;\n" +
                "import com.sinosoft.msf.utils.ModelUtils;\n" +
                "import com.sinosoft.msf.utils.FieldException;\n" +
                "\n" +
                "rule \"FIELD" + num + "\"\n" +
                "\n" +
                "when\n" +
                "    $obj : JSONObject()\n" +
                //Boolean(this == true)
                "    Boolean(this == true) from accumulate(\n" +
                "        $o : JSONObject(),\n" +
                "        init(boolean flag = false),\n" +
                "        action(\n" +
                builder.toString() +
                "        ),\n" +
                "        result(flag)\n" +
                "    )\n" +
                "then\n" +
                //   "    System.out.println($obj);\n" +
                "    JSONObject result = new JSONObject();\n" +
                "    result.put(\"ruleCode\",drools.getRule().getName());\n" +
                "    if($obj.get(\"droolsfiled\")==null){\n" +
                "       result.put(\"message\",\"" + warningInfo + "\");\n" +
                "    }else{\n" +
//                "       result.put(\"message\",\"词条不完整。\");\n" +
                "       $obj.remove(\"droolsfiled\");\n" +
                "       result.remove(\"ruleCode\");\n"+
                "       return;\n" +
                "    }\n" +
                "    if($obj.get(\"ruleMessageDTOList\")==null){\n" +
                "        $obj.put(\"ruleMessageDTOList\",new JSONArray());\n" +
                "    }\n" +
                "    $obj.getJSONArray(\"ruleMessageDTOList\").add(result);\n" +
                "end";
        return rule;
    }

    private void build(CreateRuleModel createRuleModel, StringBuilder builder, List<ModelEntity> modelEntityList) {
        createModelCoding(modelEntityList, builder);
        List<JSONObject> listJson = createRuleModel.getRuleList();
        Integer type = null;
        String value = null;
        String operationType = null;
        JSONObject json = null;
        String fieldCodePath = null;
        String field1Path = null;
        String field2Path = null;
        builder.append("try{");
        String dataTypeCode = null;
        String mathOperator = null;
        String mathDataType= null;
        StringBuilder tempBuilder = new StringBuilder();
        JSONObject dictionaryJson = null;
        Integer paramNum = null;
        if(listJson != null && !listJson.isEmpty()){
            int size = listJson.size();

            for (int i =0; i < size; i ++) {
                json = listJson.get(i);
                if(i != 0 ){
                    tempBuilder.append(createRuleModel.getTDrlDictionary().getBak1());
                }
                type = json.getInteger("type");
                if(type == null) {
                    throw new ParamException("生成规则类型为空");
                } else if(type == 1) {
                    value = StringUtils.isEmpty(json.getString("value"))?"":json.getString("value");
                    fieldCodePath = StringUtils.isEmpty(json.getString("fieldCodePath"))?"":json.getString("fieldCodePath");
                    dataTypeCode = StringUtils.isEmpty(json.getString("dataTypeCode"))?"":json.getString("dataTypeCode");
                    dictionaryJson = json.getJSONObject("dictionary");
                    paramNum = dictionaryJson.getInteger("bak1");
                    operationType = StringUtils.isEmpty(dictionaryJson.getString("code"))?"":dictionaryJson.getString("code");
                    tempBuilder.append("OperationUtils." +
                            "operation(\"" + fieldCodePath + "\","
                            + " $o,\"" +  value + "\","
                            + "\"" + operationType + "\",\"" + dataTypeCode + "\",\""+paramNum+"\")");

                } else if(type == 2) {
                    value = StringUtils.isEmpty(json.getString("value"))?"":json.getString("value");
                    dataTypeCode = StringUtils.isEmpty(json.getString("dataTypeCode"))?"":json.getString("dataTypeCode");
                    field1Path = StringUtils.isEmpty(json.getString("field1Path"))?"":json.getString("field1Path");
                    operationType = StringUtils.isEmpty(json.getString("operationType"))?"":json.getString("operationType");
                    field2Path = StringUtils.isEmpty(json.getString("field2Path"))?"":json.getString("field2Path");
                    mathOperator  = StringUtils.isEmpty(json.getString("mathOperator"))?"":json.getString("mathOperator");
                    mathDataType =  StringUtils.isEmpty(json.getString("mathDataType"))?"":json.getString("mathDataType");
                    dictionaryJson = json.getJSONObject("dictionary");
                    paramNum = dictionaryJson.getInteger("bak1");
                    operationType = StringUtils.isEmpty(dictionaryJson.getString("code"))?"":dictionaryJson.getString("code");

                    if(StringUtils.isEmpty(field1Path)||StringUtils.isEmpty(field2Path)){
                        throw  new ParamException("词条路径为空");
                    }
                    /*
                     * if(fieldCodePath2.indexOf("#") != -1 && fieldCodePath.indexOf("#") != -1){
                     * throw new ParamException("两个词条路径不能同时为数组"); }
                     */
                    tempBuilder.append("OperationUtils." +
                            "operation(\"" + field1Path + "\"" +
                            ",\"" + field2Path +
                            "\",\"" + mathOperator +
                            "\",\"" + mathDataType +
                            "\","
                            + " $o,\"" +  value + "\","
                            + "\"" + operationType + "\",\"" + dataTypeCode + "\")");
                } else {
                    throw new ParamException("生成规则类型错误");
                }

            }
        }
        builder.append("if(" +tempBuilder.toString()+"){" +
                "    flag = true;\n" +
                "    return;\n" +
                "}");
        builder.append("}catch (FieldException e){\n" +
                "$obj.put(\"droolsfiled\",1);\n" +
                "flag=true;\n"+
                "        }");
    }

    /**
     * 生成规则入口
     *
     * @param num             规则号
     * @param fieldConfig     词条路径
     * @param value           值
     * @param dictionary      运算字典
     * @param num 规则号
     * @param fieldConfig 词条路径
     * @param value 值
     * @param dictionary 运算字典
     * @param modelEntityList 模式
     * @param warningInfo
     * @return
     */
    public String createRule(Long num, TDrlFieldConfig fieldConfig, Object value, TDrlDictionary dictionary, List<ModelEntity> modelEntityList, String warningInfo) {

        String fieldPath = fieldConfig.getFieldCodePath();
        if (num == null || StringUtils.isEmpty(fieldPath) ){
            return "";
        }
        fieldPath = fieldPath.trim();
        if (fieldPath.startsWith(".")) {
            fieldPath = fieldPath.substring(1);
        }
        if (fieldPath.endsWith(".")) {
            fieldPath = fieldPath.substring(0, fieldPath.length() - 1);
        }
        StringBuilder builder = new StringBuilder();
        build(fieldConfig, builder, value, dictionary, modelEntityList);
        //String model = "cc.bb==1";
        String rule = "package com.field;\n" +
                "import com.alibaba.fastjson.JSONObject;\n" +
                "import com.alibaba.fastjson.JSONArray;\n" +
                "import com.sinosoft.msf.utils.OperationUtils;\n" +
                "import com.sinosoft.msf.utils.ModelUtils;\n" +
                "\n" +
                "rule \"FIELD" + num + "\"\n" +
                "\n" +
                "when\n" +
                "    $obj : JSONObject()\n" +
                //Boolean(this == true)
                "    Boolean(this == true) from accumulate(\n" +
                "        $o : JSONObject(),\n" +
                "        init(boolean flag = false),\n" +
                "        action(\n" +
                builder.toString() +
                "        ),\n" +
                "        result(flag)\n" +
                "    )\n" +
                "then\n" +
                //   "    System.out.println($obj);\n" +
                //   "    System.out.println($obj);\n" +
                "    JSONObject result = new JSONObject();\n" +
                "    result.put(\"ruleCode\",drools.getRule().getName());\n" +

                "    if($obj.get(\"droolsfiled\")==null){\n"+
                "       result.put(\"message\",\"" + warningInfo + "\");\n" +
                "    }else{\n" +
//                "       result.put(\"message\",\"" + fieldConfig.getFieldName() + "词条不完整。\");\n" +
                "       $obj.remove(\"droolsfiled\");\n" +
                "       result.remove(\"ruleCode\");\n"+
                "       return;\n" +
                "    }\n" +
                "    if($obj.get(\"ruleMessageDTOList\")==null){\n" +
                "        $obj.put(\"ruleMessageDTOList\",new JSONArray());\n" +
                "    }\n" +
                "    $obj.getJSONArray(\"ruleMessageDTOList\").add(result);\n" +
                "end";
        return rule;
    }

    /**
     * 叶子节点处理
     *
     * @param key
     * @param value
     * @param dictionary
     * @param builder
     * @param superName
     */
    private void leafNode(TDrlFieldConfig fieldConfig, String key, Object value, TDrlDictionary dictionary, StringBuilder builder, String superName) {
        if (StringUtils.isEmpty(dictionary.getBak1())) {
            getOperationCoding(fieldConfig, key, value, dictionary.getCode(), builder, superName);
            getOperationCoding(fieldConfig,key,value,  dictionary.getCode(), builder, superName);
            return;
        }
        switch (dictionary.getBak1()){
            case "1":
                getSingleCoding(fieldConfig, key, dictionary.getCode(), builder, superName);
                break;
            default:
                getOperationCoding(fieldConfig, key, value, dictionary.getCode(), builder, superName);
                break;
        }

    }

    /**
     * 拼接通用drools代码段
     *
     * @param key
     * @param value
     * @param operationType
     * @param builder
     * @param superName
     * @param fieldConfig
     */
    private void getOperationCoding(TDrlFieldConfig fieldConfig,String key, Object value, String operationType, StringBuilder builder, String superName) {
        builder.append("if(OperationUtils.operationTowValue("+superName+".get(\""+ key+"\"),\""+value+"\",\""+operationType+"\",\""+fieldConfig.getDataTypeCode()+"\")) {\n" +
                "    flag = true;\n" +
                "    return;\n" +
                "}\n");
    }

    /**
     * 获取是空的拼接drools代码段
     *
     * @param fieldConfig
     * @param key
     * @param operationType
     * @param builder
     * @param superName
     */
    private void getSingleCoding(TDrlFieldConfig fieldConfig, String key,String operationType ,StringBuilder builder, String superName){
        builder.append("if (OperationUtils.singleOperation("+superName+".get(\""+ key+"\"),\""+operationType+"\",\""+fieldConfig.getDataTypeCode()+"\")) {\n" +
                "    flag = true;\n" +
                "    return;\n" +
                "}\n");
    }

    /**
     * 获取拼接drools代码段结尾
     *
     * @param isSuperArray
     * @return
     */

    private String getCodingEnd(boolean isSuperArray, int i, String key){
        if(isSuperArray) {
            return "i"+(i-1)+");\n";
        } else {
            return "\"" + key + "\");\n";
        }
    }

    /**
     * 获取非空代码片段
     *
     * @param paramName
     * @param builder
     * @return
     */
    private void getIsNotEmptyCoding(String paramName, StringBuilder builder) {
        builder.append("if(" + paramName + "== null){\n" +
//                "$obj.put(\"droolsfiled\",1);\n" +
//                "flag=true;\n"
                 "          return ;\n" +
                "}\n");
    }

    /**
     * 生成模式匹配的代码片段
     *
     * @param modelEntityList
     * @param builder
     */
    private void createModelCoding(List<ModelEntity> modelEntityList, StringBuilder builder){
        if(modelEntityList == null || modelEntityList.isEmpty()){
            return;
        }
        for (ModelEntity model : modelEntityList) {
            if (null == model.getDictionary().getBak1()) {
                builder.append("if(!ModelUtils.operation(\"" + model.getFieldPath() + "\", $o,\"" + model.getValue() + "\",\"" + model.getOperationType() + "\")){\n" +

                        "flag=false;\n"
                        + "          return ;\n" +
                        "}\n");
                continue;
            }
            switch (model.getDictionary().getBak1()){
                case "1":
                    builder.append("if(!ModelUtils.singleOperation(\"" + model.getFieldPath() + "\", $o,\"" + model.getOperationType() + "\")){\n" +
                            "flag=false;\n"
                            + "          return ;\n" +
                            "}\n");
                    break;
                default:
                    builder.append("if(!ModelUtils.operation(\"" + model.getFieldPath() + "\", $o,\"" + model.getValue() + "\",\"" + model.getOperationType() + "\")){\n" +


                            "flag=false;\n"
                            + "          return ;\n" +
                            "}\n");
                    break;
            }
        }
    }

    /**
     * 生成规则
     *
     * @param fieldConfig
     * @param builder
     * @param value
     * @param dictionary
     */
    private void build(TDrlFieldConfig fieldConfig, StringBuilder builder, Object value, TDrlDictionary dictionary, List<ModelEntity> modelEntityList) {
        String[] paths = RuleCoverJsonUtils.getStringArray(fieldConfig.getFieldCodePath());
        int size = paths.length;
        boolean isArray = false;
        boolean isLeafNode = false;
        String key = null;
        String getKey = null;
        String superName = "$o";
        String paramName = null;
        boolean isSuperArray = false;
        List<String> listEnd = new ArrayList<>();
        String codingStr = null;
        createModelCoding(modelEntityList, builder);
        for (int i = 0;  i < size; i ++){
            isLeafNode = (i + 1 == size);
            key = paths[i];
            isArray = RuleCoverJsonUtils.getIsArray(key);
            getKey = RuleCoverJsonUtils.getPutKey(key, isArray);
            if(isLeafNode) {
                leafNode(fieldConfig,getKey, value, dictionary, builder, superName);
                break;
            }
            paramName = "temp" + getKey + i;
            if(isArray) {
                codingStr = "JSONArray " + paramName +" = "+superName+".getJSONArray(";
                builder.append(codingStr +getCodingEnd(isSuperArray, i, getKey));
                getIsNotEmptyCoding(paramName, builder);
                builder.append("for (int i" + i + " = 0; i" + i + " < " + paramName + ".size(); i" + i + " ++) {\n");
                if(i == (size - 2)) {
                    getIsNotEmptyCoding(paramName, builder);
                    superName = paramName;
                    paramName = "temp" + (i + 1);
                    builder.append("JSONObject " + paramName + " = " + (superName + ".getJSONObject(i" + i + ")") + ";\n");
                }
                listEnd.add("\t}\n");
            } else {
                codingStr = "JSONObject " + paramName + " = "+superName  + ".getJSONObject(";
                builder.append(codingStr + getCodingEnd(isSuperArray,i,getKey));
            }
            if (!isArray || (isArray && i == (size - 2))) {
                getIsNotEmptyCoding(paramName, builder);
            }
            superName = paramName;
            isSuperArray = isArray;
        }
        for (String end: listEnd) {
            builder.append(end);
        }
    }


}

